package kiwi.assist.dev.guieditor.command {
	import avmplus.getQualifiedClassName;

	import fl.core.UIComponent;
	import fl.data.DataProvider;

	import ghostcat.util.ReflectUtil;

	import kiwi.assist.dev.guieditor.event.GUIEditorEvent;
	import kiwi.assist.dev.guieditor.model.ContainerConfig;
	import kiwi.assist.dev.guieditor.model.PropertyConfig;
	import kiwi.assist.dev.guieditor.model.StyleConfig;
	import kiwi.assist.dev.guieditor.model.UiConfig;
	import kiwi.assist.dev.guieditor.model.UiDetailVO;
	import kiwi.assist.dev.guieditor.model.format.BooleanFormat;
	import kiwi.assist.dev.guieditor.model.format.ClassFormat;
	import kiwi.assist.dev.guieditor.model.format.DataProviderFormat;
	import kiwi.assist.dev.guieditor.model.format.FilterFormat;
	import kiwi.assist.dev.guieditor.model.format.JsonFormat;
	import kiwi.assist.dev.guieditor.model.format.NumericFormat;
	import kiwi.assist.dev.guieditor.model.format.SkinFormat;
	import kiwi.assist.dev.guieditor.model.format.StringFormat;
	import kiwi.assist.dev.guieditor.model.format.StyleFormat;
	import kiwi.assist.dev.guieditor.model.format.TFFormat;
	import kiwi.assist.dev.util.SkinComponentAdapter;
	import kiwi.debug.Log;
	import kiwi.util.ArrayUtils;
	import kiwi.util.sprintf;

	import org.robotlegs.mvcs.Command;

	import flash.events.Event;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.text.TextFormat;

	/**
	 * 保存ui
	 * 
	 * @author zhangming.luo
	 */
	public class SaveUiCommand extends Command {
		[Inject]
		public var detail : UiDetailVO;
		[Inject]
		public var event : GUIEditorEvent;
		private var xml : XML = <config><container></container><background></background><uis></uis></config>;

		override public function execute() : void {
			super.execute();
			appendUi(XML(xml.container), detail.containerImpl, detail.container);
			for each (var skin:SkinComponentAdapter in detail.backgroundSkinList) {
				appendBackground(XML(xml.background), skin);
			}
			var len : int = detail.uiList.length;
			for (var i : int = 0;i < len;i++) {
				var impl : UIComponent = UIComponent(detail.uiList[i]);
				var config : UiConfig = detail.configList[impl];
				if (config is ContainerConfig) {
					continue;
				}
				appendUi(XML(xml.uis), impl, config);
			}
			var output : FileStream;
			if (event.data && event.data.isAutoSave && detail.name != "noname") {
				// 重命名自动保存
				output = new FileStream();
				output.open(File.applicationDirectory.resolvePath(detail.projectPath + "/" + detail.name + ".autosave"), FileMode.WRITE);
				output.writeUTFBytes(xml.toXMLString());
				output.close();
			} else if (detail.name == "noname") {
				// 还没有保存过
				saveFile();
			} else {
				// 直接保存
				output = new FileStream();
				output.open(File.applicationDirectory.resolvePath(detail.projectPath + "/" + detail.name + ".ui"), FileMode.WRITE);
				output.writeUTFBytes(xml.toXMLString());
				output.close();
				Log.alert("保存完毕");
			}
		}

		private function saveFile() : void {
			var file : File = new File();
			file.addEventListener(Event.COMPLETE, function() : void {
				// 重新保存一个texture到sprite所在的目录
				if (file.name.indexOf(".") > 0) {
					// 剔除多余的扩展名
					detail.name = file.name.substring(0, file.name.indexOf("."));
				} else {
					detail.name = file.name.replace(".ui", "");
				}
				detail.projectPath = file.parent.nativePath;
				detail.dirty = false;
				Log.alert("保存完毕");
			});
			file.save(xml.toXMLString(), detail.name + ".ui");
		}

		private function appendUi(xml : XML, impl : UIComponent, config : UiConfig) : XML {
			if (!impl) {
				return null;
			}
			try {
				var name : QName = ReflectUtil.getQName(impl);
				var x : XML = new XML(sprintf("<%s></%s>", name.localName, name.localName));
				var prefix : String;
				if (name.uri) {
					prefix = ArrayUtils.transform(String(name.uri).split("."), function(e : String) : String {
						return e.charAt(0);
					}).join("");
					x.setNamespace(new Namespace(prefix, name.uri));
				} else {
					prefix = null;
				}
				for each (var property:PropertyConfig in config.propertyList) {
					if (property.format is StringFormat || property.format is NumericFormat || property.format is BooleanFormat) {
						x.appendChild(createXMLByObject(property.key, impl[property.key]));
					} else if (property.format is DataProviderFormat) {
						var xmlStr : String = "";
						for each (var item:* in DataProvider(impl[property.key]).toArray()) {
							xmlStr += new XML(sprintf("<item>%s</item>", createXMLByObject("Object", item).toXMLString())).toXMLString();
						}
						x.appendChild(new XML(sprintf("<%s>%s</%s>", property.key, xmlStr, property.key)));
					} else if (property.format is JsonFormat) {
						if (impl[property.key] is Array) {
							x.appendChild(createXMLByObject(property.key, impl[property.key]));
						} else {
							x.appendChild(new XML(sprintf("<%s>%s</%s>", property.key, createXMLByObject("Object", impl[property.key]).toXMLString(), property.key)));
						}
					} else {
						// Pass
					}
				}
				x.appendChild(createXMLByObject("x", impl.x));
				x.appendChild(createXMLByObject("y", impl.y));
				for each (var style:StyleConfig in config.styleList) {
					var value : Object = impl.getStyle(style.key);
					if (value == null) {
						continue;
					}
					if (style.format is SkinFormat) {
						if (value is String) {
							x.appendChild(new XML(sprintf("<style name=\"%s\" format=\"Skin\">%s</style>", style.key, value)));
						} else {
							x.appendChild(new XML(sprintf("<style name=\"%s\" format=\"Skin\">%s</style>", style.key, getQualifiedClassName(value))));
						}
					} else if (style.format is TFFormat) {
						if (value is String ) {
							x.appendChild(new XML(sprintf("<style name=\"%s\" format=\"TextFormat\">%s</style>", style.key, createXMLByObject(ReflectUtil.getQName(value).toString(), {}).toXMLString())));
						} else if (value is Class && value != TextFormat) {
							x.appendChild(new XML(sprintf("<style name=\"%s\" format=\"TextFormat\">%s</style>", style.key, createXMLByObject(ReflectUtil.getQName(value).toString(), {}).toXMLString())));
						} else if (ReflectUtil.getClass(value) != TextFormat) {
							x.appendChild(new XML(sprintf("<style name=\"%s\" format=\"TextFormat\">%s</style>", style.key, createXMLByObject(ReflectUtil.getQName(value).toString(), {}).toXMLString())));
						} else {
							x.appendChild(new XML(sprintf("<style name=\"%s\" format=\"TextFormat\">%s</style>", style.key, createXMLByObject("flash.text::TextFormat", {align:value.align, size:value.size, color:value.color, font:value.font, bold:value.bold, italic:value.italic}))));
						}
					} else if (style.format is StyleFormat) {
						var styleXML : XML = createXMLByObject(ReflectUtil.getQName(value).toString(), {});
						x.appendChild(new XML(sprintf("<style name=\"%s\" format=\"Style\">%s</style>", style.key, styleXML.toXMLString())));
					} else if (style.format is FilterFormat) {
						x.appendChild(new XML(sprintf("<style name=\"%s\" format=\"Filter\">%s</style>", style.key, value is String ? value : getQualifiedClassName(value))));
					} else if (style.format is ClassFormat) {
						x.appendChild(new XML(sprintf("<style name=\"%s\" format=\"Class\">%s</style>", style.key, getQualifiedClassName(value))));
					} else {
						x.appendChild(new XML(sprintf("<style name=\"%s\" format=\"%s\">%s</style>", style.key, style.format["name"], value)));
					}
				}
				var xx : XML = new XML(sprintf("<ui comp=\"%s\"></ui>", config.comp));
				xx.appendChild(x);
				xml.appendChild(xx);
				return xx;
			} catch(e : Error) {
				Log.error("保存控件时出现错误", e);
			}
			return null;
		}

		private function appendBackground(xml : XML, impl : SkinComponentAdapter) : void {
			var clzName : String;
			if (impl.skin.clz == null) {
				clzName = impl.skin.name;
			} else {
				clzName = ReflectUtil.getQName(impl.skin.clz).toString();
			}
			if (impl.name.indexOf("instance") == 0 || impl.name == "noname") {
				xml.appendChild(createXMLByObject(clzName, {width:impl.width, height:impl.height, x:impl.x, y:impl.y}));
			} else {
				xml.appendChild(createXMLByObject(clzName, {name:impl.name, width:impl.width, height:impl.height, x:impl.x, y:impl.y}));
			}
		}

		private function createXMLByObject(title : String, obj : *) : XML {
			var xml : XML;
			var nameSpace : Namespace;
			if (title.indexOf("*::") == 0) {
				title = title.replace("*::", "");
			}
			if (title.indexOf("::") > 0) {
				var uri : String = title.substr(0, title.indexOf("::"));
				if (uri) {
					nameSpace = new Namespace(ArrayUtils.transform(uri.split("."), function(e : String) : String {
						return e.charAt();
					}).join(""), uri);
					title = title.substr(title.indexOf("::") + 2);
				}
			}
			xml = new XML(sprintf("<%s></%s>", title, title));
			nameSpace && xml.setNamespace(nameSpace);
			if (obj is int || obj is Number || obj is String || obj is Boolean || obj is uint) {
				xml.appendChild(obj);
				return xml;
			}
			for (var key:String in obj) {
				var subXML : XML;
				if (obj[key] is Array) {
					subXML = new XML(sprintf("<%s></%s>", key, key));
					for each (var subObj:* in obj[key]) {
						subXML.appendChild(createXMLByObject("item", subObj));
					}
				} else {
					subXML = createXMLByObject(key, obj[key]);
				}
				xml.appendChild(subXML);
			}
			return xml;
		}
	}
}
